let fs = require('fs');
let path = require('path');
let crypto = require('crypto');
let spawn = require('child_process');

//远程服务器地址
const remoteResUrl = '';
//本地svn目录
const remoteSvnPath = '../hfs';

// 参数指定的版本号  第一次制定版本号0.0.1
let version;
// 是否处理svn
let isSvn = true;
// 是否保持版本，不自增
let isKeep = false;
// 是否为生产环境
let isRemote = true;
//指定更新年纪 为0不指定全部更新
let Grade = 1;

// 分析参数
let i = 2;
while (i < process.argv.length) {
    let arg = process.argv[i];
    switch (arg) {
        case '--version' :
        case '-v' :
            version = process.argv[i + 1];
            i += 2;
            break;
        case '--svn':
            isSvn = true;
            i += 1;
            break;
        case '--keep':
            isKeep = true;
            i += 1;
            break;
        case '--remote':
            isRemote = true;
            i += 1;
        case '--grade':
            Grade = process.argv[i + 1];
            i += 2;
            break;
        default :
            i++;
            break;
    }
}

let url = remoteResUrl;
let svn = remoteSvnPath;
let updatePath = [];

if (!url.endsWith('/')) url += '/';

if (!version) {
    if (!isSvn) {
        console.error('请指定version');
        return;
    }
}

// 如果指定了SVN，得先更新SVN, 从SVN中获取版本号
console.info('[svn update...]');
spawn.execSync('svn update ' + svn).toString();


let resPath = './';
let buildCount = 0;
let buildSuccessedCount = 0;

//构建全部
if (Grade == 0) {
    let stat = fs.statSync(resPath);
    if (!stat.isDirectory()) {
        return;
    }
    let subpaths = fs.readdirSync(resPath);
    for (let i = 0; i < subpaths.length; ++i) {
        // 忽略已.开头的路径
        if (subpaths[i][0] === '.') {
            continue;
        }
        let subpath = path.join(resPath, subpaths[i]);
        stat = fs.statSync(subpath);
        if (stat.isDirectory()) {
            buildCount++;
            updatePath.push(subpaths[i]);
            build(subpath, subpaths[i]);
        }
    }
} else {
    //构建单个年纪
    buildCount++;
    updatePath.push(Grade.toString());
    build(resPath + Grade, Grade)
}


function build(src, grade) {
    //
    if (!version) {
        let oldVersion = readVersion(path.join(svn, grade.toString()))
        if (isKeep) {
            version = oldVersion;
            console.info(`保持版本, ${oldVersion} -> ${version}`);
        } else {
            version = nextVersion(oldVersion);
            console.info(`提升版本, ${oldVersion} -> ${version}`);
        }
    }

    //拼凑manifest
    let manifest = {
        packageUrl: url + grade,
        remoteManifestUrl: url + grade + "/" + 'project.manifest',
        remoteVersionUrl: url + grade + "/" + 'version.manifest',
        version: version,
        assets: {},
        searchPaths: []
    };

    //从remote目录下获取Manifest信息
    console.info('构建manifest文件...')
    readDir(src, grade + "/", manifest.assets);

    // 生成project.manifest和version.manifest
    console.info('保存manifest文件...')
    let destProject = path.join(src, 'project.manifest');
    let destVersion = path.join(src, 'version.manifest');

    // 写文件
    fs.writeFile(destProject, JSON.stringify(manifest), (err) => {
        if (err) throw err;
        console.log(destProject + ' successfully generated');

        delete manifest.assets;
        delete manifest.searchPaths;
        fs.writeFile(destVersion, JSON.stringify(manifest), (err) => {
            if (err) throw err;
            console.log(destVersion + ' successfully generated');
            buildSuccessedCount++;
            //从dest中拷贝文件至svn
            if (svn) {
                //这里有点问题，应该指定更新的目录
                if (buildSuccessedCount == buildCount) doSvn();
            } else {
                console.info('success!');
            }
        });
    });
}


function doSvn() {
    console.info('[svn update...]');
    spawn.exec('svn update ' + svn, function (error, stdout) {
        if (error) {
            throw error;
        }
        if (stdout) console.info(stdout);

        console.info('从remote中拷贝资源至svn中');

        // 删除svn目录下的src, res, version， project
        for (let k of updatePath) {
            let destPath = path.join(svn, k);
            let srcPath = path.join(resPath, k);
            rmSubDir(destPath);
            copyDir(srcPath, destPath);
            console.log(srcPath + " copy to " + destPath);
        }

        console.info('success! 记得手动提交SVN');
        // let svnadd = "svn st | awk '{if ($1 == \"?\") {print $2}}' | xargs svn add";
        // let svndel = "svn st | awk '{if ($1 == \"!\") {print $2}}' | xargs svn rm";
        // let svncommit = "svn commit --force-log -m \"" + version + "\"";
        //
        // // 执行svndel
        // console.info('[svn rm...]');
        // spawn.exec(svndel, {
        //     cwd: svn,
        // }, function (error, stdout) {
        //     if (error) {
        //         throw error;
        //     }
        //     if (stdout) console.info(stdout);
        //     // 执行svnadd
        //     console.info('[svn add...]');
        //     spawn.exec(svnadd, {
        //         cwd: svn,
        //     }, function (error, stdout) {
        //         if (error) {
        //             throw error;
        //         }
        //         if (stdout) console.info(stdout);
        //         // 执行svn commit
        //         console.info('[svn commit...]');
        //         spawn.exec(svncommit, {
        //             cwd: svn,
        //         }, function (error, stdout) {
        //             if (error) {
        //                 throw error;
        //             }
        //             if (stdout) console.info(stdout);
        //             console.info('success!');
        //         });
        //     });
        // });
    });
}


// 拷贝资源
function copyDir(src, dest) {
    let stat = fs.statSync(src);
    if (!stat.isDirectory()) {
        return;
    }
    // 创建目标目录
    if (!fs.existsSync(dest)) {
        mkDir(dest);
    }

    let subpaths = fs.readdirSync(src);
    for (let i = 0; i < subpaths.length; ++i) {
        // 忽略已.开头的路径
        if (subpaths[i][0] === '.') {
            continue;
        }
        let subpath = path.join(src, subpaths[i]);
        stat = fs.statSync(subpath);
        if (stat.isDirectory()) {
            copyDir(subpath, path.join(dest, subpaths[i]));
        } else if (stat.isFile()) {
            let name = path.basename(subpath);
            if (name == "version.js" || name == "package.json") continue;
            fs.writeFileSync(path.join(dest, subpaths[i]), fs.readFileSync(subpath));
        }
    }
}

function copyFile(src, dest) {
    let stat = fs.statSync(src);
    if (!stat.isFile()) {
        return;
    }
    let readable = fs.createReadStream(src);//创建读取流
    let writable = fs.createWriteStream(dest);//创建写入流
    readable.pipe(writable);
}

// 读取目录下所有的文件并生成manifest结构
function readDir(dir, rootDir, obj) {
    let stat = fs.statSync(dir);
    if (!stat.isDirectory()) {
        return;
    }
    let subpaths = fs.readdirSync(dir), subpath, size, md5, compressed, relative;
    for (let i = 0; i < subpaths.length; ++i) {
        if (subpaths[i][0] === '.') {
            continue;
        }
        subpath = path.join(dir, subpaths[i]);
        stat = fs.statSync(subpath);
        if (stat.isDirectory()) {
            readDir(subpath, rootDir, obj)
        } else {
            // Size in Bytes
            size = stat['size'];
            md5 = crypto.createHash('md5').update(fs.readFileSync(subpath, 'binary')).digest('hex');
            compressed = path.extname(subpath).toLowerCase() === '.zip';

            relative = path.relative(rootDir, subpath);
            relative = relative.replace(/\\/g, '/');
            relative = encodeURI(relative);
            obj[relative] = {
                'size': size,
                'md5': md5
            };
            if (compressed) {
                obj[relative].compressed = true;
            }
        }
    }
}

// 移除目录
function rmPath(file) {
    if (!fs.existsSync(file)) {
        return;
    }
    let stat = fs.statSync(file);
    if (stat.isFile()) {
        fs.unlinkSync(file);
        return;
    }
    // 目录需要递归删除
    let subpaths = fs.readdirSync(file);
    for (let i = 0; i < subpaths.length; ++i) {
        let subpath = path.join(file, subpaths[i]);
        if (subpaths[i][0] === '.') {
            continue;
        }
        rmPath(subpath);
    }
    fs.rmdirSync(file);
}

function rmSubDir(file) {
    if (!fs.existsSync(file)) {
        return;
    }
    let stat = fs.statSync(file);
    if (stat.isFile()) return;

    let subpaths = fs.readdirSync(file);
    for (let i = 0; i < subpaths.length; i++) {
        let subpath = path.join(file, subpaths[i]);
        stat = fs.statSync(subpath);
        // 删除子目录
        if (stat.isDirectory()) rmPath(subpath);
    }
}

// 创建目录
function mkDir(path) {
    try {
        fs.mkdirSync(path);
    } catch (e) {
        if (e.code !== 'EEXIST') throw e;
    }
}

// 获取下一个版本号, 支持3个版本号
function nextVersion(version) {
    let arr = version.split('.');
    // 从后面递增, 超过999就往前加1
    for (let i = arr.length - 1; i >= 0; i--) {
        let val = Number(arr[i]);
        if (val >= 999) {
            arr[i] = 0;
            continue;
        }
        // 版本号自增1
        val += 1;
        arr[i] = val;
        break;
    }
    // 构建字符串
    return arr.join('.');
}

function readVersion(dir) {
    let buffer = fs.readFileSync(path.join(dir, 'version.manifest'))
    let json = JSON.parse(buffer.toString());
    return json.version
}